package ai.people.platform.system.service.impl;

import ai.people.core.grpc.lib.user.*;
import ai.people.core.grpc.utils.ProtoJsonUtil;
import ai.people.core.grpc.utils.StreamObserverDelegate;
import ai.people.netmon.framework.domain.system.entity.NmSystemMenu;
import ai.people.netmon.framework.domain.system.entity.NmSystemRole;
import ai.people.netmon.framework.domain.system.entity.NmSystemUser;
import ai.people.netmon.framework.domain.system.entity.NmSystemUserInfo;
import ai.people.netmon.framework.domain.system.request.SystemUserRequest;
import ai.people.netmon.framework.domain.system.request.UpdatePasswordParam;
import ai.people.netmon.framework.domain.system.vo.*;
import ai.people.netmon.framework.domain.ucenter.entity.NmSysUser;
import ai.people.netmon.framework.exception.enums.AccountExceptionEnum;
import ai.people.netmon.framework.exception.enums.CommonEnum;
import ai.people.netmon.framework.exception.enums.SystemExceptionEnum;
import ai.people.netmon.framework.model.response.PageResponse;
import ai.people.netmon.framework.utils.AssertUtils;
import ai.people.platform.system.mapper.SystemUserMapper;
import ai.people.platform.system.service.SystemMenuService;
import ai.people.platform.system.service.SystemRoleService;
import ai.people.platform.system.service.SystemUserInfoService;
import ai.people.platform.system.service.SystemUserService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.protobuf.Empty;
import com.google.protobuf.Int64Value;
import io.grpc.stub.StreamObserver;
import lombok.RequiredArgsConstructor;
import net.devh.boot.grpc.server.service.GrpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 系统用户服务impl
 *
 * @author yuanqinglong
 * @date 2022/3/4 15:53
 */
@GrpcService
@RequiredArgsConstructor
public class SystemUserServiceImpl extends UserServiceGrpc.UserServiceImplBase implements SystemUserService {


    private static final Logger logger = LoggerFactory.getLogger(SystemUserServiceImpl.class);

    /**
     * 系统用户映射器
     */
    private final SystemUserMapper systemUserMapper;

    /**
     * 系统用户信息服务impl
     */
    private final SystemUserInfoService systemUserInfoServiceImpl;

    /**
     * 系统角色服务
     */
    private final SystemRoleService systemRoleService;

    /**
     * 系统菜单服务
     */
    private final SystemMenuService systemMenuService;

    /**
     * 密码编码器
     */
    private final PasswordEncoder passwordEncoder;


    /**
     * <pre>
     * *
     * 登录用户信息
     * </pre>
     *
     * @param request          请求
     * @param responseObserver 响应观察者
     */
    @Override
    public void loginUserInfo(LoginRequest request, StreamObserver<LoginResponse> responseObserver) {
        logger.info("loginUserInfo:" + request.getUsername());
        StreamObserverDelegate.build(responseObserver).execute(() -> {
            NmSystemLoginUserVO longinUserByAccount = this.getLonginUserByAccount(request.getUsername());
            return LoginResponse.newBuilder().setData(JSON.toJSONString(longinUserByAccount)).build();
        });
    }

    /**
     * 更新最后登录时间
     * </pre>
     *
     * @param request          请求
     * @param responseObserver 响应观察者
     */
    @Override
    public void updateLastLoginTime(Int64Value request, StreamObserver<Empty> responseObserver) {
        StreamObserverDelegate.build(responseObserver).execute(() -> {
            this.updateLastLoginTime(request.getValue());
            return null;
        });
    }

    /**
     * 非管理员用户列表
     *
     * @param request          请求
     * @param responseObserver 响应观察者
     */
    @Override
    public void listNonAdminUsers(Empty request, StreamObserver<NonAdminUserResponse> responseObserver) {
        StreamObserverDelegate.build(responseObserver).execute(() -> {
            List<NmSystemUserSimpleVO> nmSystemUserSimpleVOS = this.listNonAdminUsers();
            NonAdminUserResponse.Builder newBuilder = NonAdminUserResponse.newBuilder();
            nmSystemUserSimpleVOS.forEach(nmSystemUserSimpleVO -> newBuilder.addUserInfo((UserSimpleInfo)ProtoJsonUtil.toProtoMessage(UserSimpleInfo.newBuilder(), JSON.toJSONString(nmSystemUserSimpleVO))));
            return newBuilder.build();
        });
    }

    /**
     * 通过账号查询用户
     *
     * @param account 账户
     * @return {@link NmSysUser}
     */
    @Override
    public NmSystemUserVO getUserByAccount(String account) {
        NmSystemUserVO nmSysUser = systemUserMapper.getUserInfoByAccount(account);
        AssertUtils.isNotNull(nmSysUser, AccountExceptionEnum.ACCOUNT_DOES_NOT_EXIST);
        nmSysUser.setRoleName(getRoleNames(nmSysUser.getId()));
        return nmSysUser;
    }

    /**
     * 通过帐户获取longin用户信息
     *
     * @param account 账户
     * @return {@link NmSystemLoginUserVO}
     */
    @Override
    public NmSystemLoginUserVO getLonginUserByAccount(String account) {
        NmSystemUserVO nmSystemUser = this.getUserByAccount(account);
        List<NmSystemRole> nmSystemRoles = systemRoleService.userRoles(nmSystemUser.getId());
        AssertUtils.isFalse(CollectionUtils.isEmpty(nmSystemRoles), AccountExceptionEnum.ACCOUNT_IS_NOT_ASSIGNED_A_ROLE);
        String roleNames = nmSystemRoles.stream().map(NmSystemRole::getName).collect(Collectors.joining(","));
        nmSystemUser.setRoleName(roleNames);
        List<NmSystemMenu> nmSystemMenus = systemMenuService.listUserMenus(nmSystemUser.getId());
        AssertUtils.isFalse(CollectionUtils.isEmpty(nmSystemMenus), AccountExceptionEnum.ACCOUNT_IS_NOT_ASSIGNED_A_MENU);
        NmSystemLoginUserVO nmSystemLoginUserVO = new NmSystemLoginUserVO();
        nmSystemLoginUserVO.setNmSystemUserVO(nmSystemUser);
        List<NmSystemUserMenu> userMenuList = nmSystemMenus.stream().map(NmSystemUserMenu::new).collect(Collectors.toList());
        nmSystemLoginUserVO.setNmSystemMenu(userMenuList);
        List<NmSystemRoleVO> systemRoleVOList = nmSystemRoles.stream().map(NmSystemRoleVO::new).collect(Collectors.toList());
        nmSystemLoginUserVO.setNmSystemRole(systemRoleVOList);
        return nmSystemLoginUserVO;
    }

    /**
     * 通过id查询用户
     *
     * @param userId 用户id
     * @return {@link NmSystemUser}
     */
    @Override
    public NmSystemUserVO getUserById(Long userId) {
        NmSystemUserVO nmSystemUser = systemUserMapper.getUserInfoById(userId);
        AssertUtils.isNotNull(nmSystemUser, SystemExceptionEnum.ACCOUNT_DOES_NOT_EXIST);
        String roleNames = this.getRoleNames(userId);
        nmSystemUser.setRoleName(roleNames);
        return nmSystemUser;
    }


    /**
     * 通过账号更新密码
     *
     * @param updatePasswordParam 参数
     * @return {@link NmSystemUserVO}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public NmSystemUserVO updatePasswordByAccount(UpdatePasswordParam updatePasswordParam) {
        int passwordByAccount = systemUserMapper.updatePasswordByAccount(updatePasswordParam.getAccount(), updatePasswordParam.getPassword());
        NmSystemUserVO userByAccount = this.getUserByAccount(updatePasswordParam.getAccount());
        userByAccount.setPassword(null);
        return userByAccount;
    }

    /**
     * 用户列表
     *
     * @param systemUserRequest 系统用户请求
     * @return {@link PageResponse}<{@link NmSystemUser}>
     */
    @Override
    public PageResponse<NmSystemUserVO> listUsers(SystemUserRequest systemUserRequest) {
        IPage<NmSystemUserVO> page = new Page<>(systemUserRequest.getOriginPageNo(), systemUserRequest.getPageSize());
        IPage<NmSystemUserVO> listUsers = systemUserMapper.listUsers(page, systemUserRequest.getSearchKeywords());
        return PageResponse.builder(listUsers);
    }

    /**
     * 非管理员用户列表
     *
     * @return {@link List}<{@link NmSystemUserSimpleVO}>
     */
    @Override
    public List<NmSystemUserSimpleVO> listNonAdminUsers() {
        return systemUserMapper.listNonAdminUsers();
    }

    /**
     * 添加系统用户
     *
     * @param nmSystemUser     系统用户
     * @param nmSystemUserInfo 系统用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSystemUser(NmSystemUser nmSystemUser, NmSystemUserInfo nmSystemUserInfo) {
        LambdaQueryWrapper<NmSystemUser> lambdaQuery = Wrappers.lambdaQuery(NmSystemUser.class);
        lambdaQuery.select(NmSystemUser::getId).eq(NmSystemUser::getAccount, nmSystemUser.getAccount());
        List<NmSystemUser> systemUserList = systemUserMapper.selectList(lambdaQuery);
        AssertUtils.isTrue(systemUserList.isEmpty(), SystemExceptionEnum.ACCOUNT_ALREADY_EXISTS);

        String encodePassword = passwordEncoder.encode(nmSystemUser.getPassword());
        nmSystemUser.setPassword(encodePassword);

        int insertResult = systemUserMapper.insert(nmSystemUser);
        AssertUtils.isTrue(insertResult > 0, CommonEnum.FAIL);
        nmSystemUserInfo.setId(nmSystemUser.getId());
        systemUserInfoServiceImpl.addSystemUserInfo(nmSystemUserInfo);
    }

    /**
     * 更新用户
     *
     * @param nmSystemUser     系统用户
     * @param nmSystemUserInfo 系统用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(NmSystemUser nmSystemUser, NmSystemUserInfo nmSystemUserInfo) {
        this.checkUserExists(nmSystemUser.getId());
        LambdaQueryWrapper<NmSystemUser> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.select(NmSystemUser::getId).eq(NmSystemUser::getAccount, nmSystemUser.getAccount()).ne(NmSystemUser::getId, nmSystemUser.getId());
        List<NmSystemUser> systemUserList = systemUserMapper.selectList(lambdaQuery);
        AssertUtils.isTrue(systemUserList.isEmpty(), SystemExceptionEnum.ACCOUNT_ALREADY_EXISTS);
        if (Objects.nonNull(nmSystemUser.getPassword())) {
            String encodePassword = passwordEncoder.encode(nmSystemUser.getPassword());
            nmSystemUser.setPassword(encodePassword);
        }
        nmSystemUser.setUpdateTime(LocalDateTime.now());
        int updateResult = systemUserMapper.updateById(nmSystemUser);
        AssertUtils.isTrue(updateResult > 0, CommonEnum.FAIL);
        systemUserInfoServiceImpl.updateUserInfo(nmSystemUserInfo);
    }

    /**
     * 删除用户
     *
     * @param userId 用户id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUser(Long userId) {
        NmSystemUser nmSystemUser = systemUserMapper.selectById(userId);
        AssertUtils.isNotNull(nmSystemUser, AccountExceptionEnum.ACCOUNT_DOES_NOT_EXIST);
        int deleteResult = systemUserMapper.deleteById(userId);
        AssertUtils.isTrue(deleteResult > 0, CommonEnum.FAIL);
        systemUserInfoServiceImpl.deleteUserInfo(userId);
    }

    /**
     * 检查用户是否存在
     *
     * @param userId 用户id
     */
    @Override
    public void checkUserExists(Long userId) {
        NmSystemUser nmSystemUser = systemUserMapper.selectById(userId);
        AssertUtils.isTrue(Objects.nonNull(nmSystemUser), SystemExceptionEnum.ACCOUNT_DOES_NOT_EXIST);
    }

    /**
     * 更新最后登录时间
     *
     * @param userId 用户id
     */
    @Override
    public void updateLastLoginTime(Long userId) {
        NmSystemUser nmSystemUser = new NmSystemUser();
        nmSystemUser.setId(userId);
        nmSystemUser.setModifyTime(LocalDateTime.now());
        systemUserMapper.updateById(nmSystemUser);
    }

    /**
     * 获得角色名称
     *
     * @param userId 用户id
     * @return {@link String}
     */
    private String getRoleNames(Long userId) {
        List<NmSystemRole> nmSystemRoles = systemRoleService.userRoles(userId);
        return nmSystemRoles.stream().map(NmSystemRole::getName).collect(Collectors.joining(","));
    }
}
